package com.zmn.oms.business.impl.worktrack;

import com.alibaba.fastjson.JSON;
import com.alibaba.nacos.api.config.annotation.NacosValue;
import com.google.common.collect.Maps;
import com.zmn.base.oms.common.model.es.orderwork.EsWorkTrack;
import com.zmn.base.common.data.common.constant.TagConsts;
import com.zmn.base.common.data.common.dro.tags.TagsDRO;
import com.zmn.common.utils.date.DateUtil;
import com.zmn.common.utils.number.NumberUtil;
import com.zmn.consts.GlobalConsts;
import com.zmn.oms.business.interfaces.base.BaseCodeService;
import com.zmn.oms.business.interfaces.eventsnotice.EventsNoticeBService;
import com.zmn.oms.business.interfaces.messageV1.app.MessageSendAppService;
import com.zmn.oms.business.interfaces.mq.MqProviderService;
import com.zmn.oms.business.interfaces.orderstock.OrderStockBService;
import com.zmn.oms.business.interfaces.worktrack.WorkTrackBService;
import com.zmn.oms.common.constant.MessageConsts;
import com.zmn.oms.common.constant.OmsEventsConsts;
import com.zmn.oms.common.constant.OrderStatusConsts;
import com.zmn.oms.common.constant.ProductConsts;
import com.zmn.oms.common.exception.OmsBaseException;
import com.zmn.oms.model.entity.conf.channel.ConfOrderChannel;
import com.zmn.oms.model.entity.masterworking.MasterWorking;
import com.zmn.oms.model.entity.omstrack.OrderWorkTrack;
import com.zmn.oms.model.entity.work.OrderWork;
import com.zmn.oms.model.vo.work.OperatePermissionVO;
import com.zmn.oms.services.interfaces.conf.channel.ConfOrderChannelService;
import com.zmn.oms.services.interfaces.masterworking.MasterWorkingService;
import com.zmn.oms.services.interfaces.order.OrderChangeService;
import com.zmn.oms.services.interfaces.work.OrderWorkService;
import com.zmn.oms.services.interfaces.work.masterwork.MasterWorkService;
import com.zmn.oms.services.interfaces.worktrack.WorkTrackService;
import com.zmn.saas.common.utils.EmojiUtil;
import com.zmn.track.common.constant.TrackConfigConsts;
import com.zmn.track.common.constant.TrackConsts;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.dubbo.config.annotation.Reference;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @ClassName OmsTrackBServiceImpl
 * @description:
 * @author: wangyanci
 * @create: 2021-05-19 16:52
 * @Version 1.0
 **/
@Slf4j
@Service
public class WorkTrackBServiceImpl implements WorkTrackBService {

    @Autowired
    private WorkTrackService workTrackService;
    @Autowired
    private MasterWorkingService masterWorkingService;
    @Autowired
    private MasterWorkService masterWorkService;
    @Autowired
    private OrderChangeService orderChangeService;
    @Autowired
    private OrderWorkService orderWorkService;
    @Autowired
    private MessageSendAppService messageSendAppService;
    @Autowired
    private OrderStockBService orderStockBService;
    @Autowired
    private EventsNoticeBService eventsNoticeBService;
    @Autowired
    protected BaseCodeService baseCodeService;
    @Resource
    private ConfOrderChannelService confOrderChannelService;

   // @Reference(version = com.zmn.base.engineer.common.constants.DubboConsts.INTERFACE_VERSION, check = false)
    //private TouchModifyRemoteService touchModifyRemoteService;

    @Autowired
    private MqProviderService mqProviderService;

//    @NacosValue(value = "${oms.non.cancel.directly.channel.id:}", autoRefreshed = true)
//    private String nonCancelDirectlyChannels;

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void deleteAndAddTrack(OrderWorkTrack orderWorkTrack) {
        if (Objects.isNull(orderWorkTrack)) {
            return;
        }
        if (StringUtils.isNotBlank(orderWorkTrack.getCreater())) {
            orderWorkTrack.setCreater(EmojiUtil.filterEmoji(orderWorkTrack.getCreater()));
        }
        if (StringUtils.isNotBlank(orderWorkTrack.getUpdater())) {
            orderWorkTrack.setUpdater(EmojiUtil.filterEmoji(orderWorkTrack.getUpdater()));
        }
        workTrackService.delete(orderWorkTrack.getOrderId(), orderWorkTrack.getWorkId(), orderWorkTrack.getTrackType());
        workTrackService.insert(orderWorkTrack);
    }

    /**
     * 操作权限
     *
     * @param orderId
     * @param workId
     * @return
     */
    @Override
    public OperatePermissionVO getOperatePermissionByTrack(Long orderId, Long workId) {
        List<OrderWorkTrack> trackList = workTrackService.getWorkTrackByTrackTypeListSrcMaster(orderId, workId, TrackConfigConsts.TRACK_CONTENT_ID_CANCEL);
        if (CollectionUtils.isEmpty(trackList)) {
            return OperatePermissionVO.success();
        }

        List<OrderWorkTrack> list = trackList.stream().filter(track -> TrackConfigConsts.TRACK_CONTENT_ID_CANCEL.contains(track.getTrackType())).collect(Collectors.toList());
        if (CollectionUtils.isEmpty(list)) {
            return OperatePermissionVO.success();
        }

        // 未完结
        Optional<OrderWorkTrack> unFinishedTrack = list.stream().filter(track -> !Objects.equals(TrackConsts.TRACK_STATUS_FINISHED, track.getTrackStatus())).findAny();
        if (unFinishedTrack.isPresent()) {
            return OperatePermissionVO.fail("有进行中的用户取消申请跟单，不可操作");
        }

        // 已完结，已同意
        Optional<OrderWorkTrack> any = list.stream().filter(track -> Objects.equals(TrackConsts.TRACK_STATUS_FINISHED, track.getTrackStatus())
                && Objects.equals(track.getHandleResult(), TrackConsts.TRACK_CONTENT_TYPE_LEVEL_ONE)).findAny();
        if (any.isPresent()) {
            return OperatePermissionVO.fail("有已同意取消未处理的跟单，不可操作");
        }
        return OperatePermissionVO.success();
    }


    @Override
    public Integer getUserWaitCancelStatus(List<OrderWorkTrack> trackList) {
        OrderWorkTrack cancelTrack = this.getCancelTrack(trackList);
        if (cancelTrack != null) {
            return GlobalConsts.YES;
        } else {
            return GlobalConsts.NO;
        }
    }

    @Override
    public Integer getMasterWaitCancelStatus(List<EsWorkTrack> trackList) {
        if (CollectionUtils.isEmpty(trackList)) {
            return null;
        }

        EsWorkTrack cancelTrack = trackList.stream()
                .filter(track -> TrackConfigConsts.TRACK_CONTENT_ID_CANCEL.contains(track.getTrackType()))
                .filter(track -> !Objects.equals(TrackConsts.TRACK_STATUS_FINISHED, track.getTrackStatus()))
                .findFirst().orElse(null);
        if (cancelTrack != null) {
            return GlobalConsts.YES;
        } else {
            return GlobalConsts.NO;
        }
    }

    @Override
    public OrderWorkTrack getMasterWaitCancelTrack(Long orderId, Long workId) {
        List<OrderWorkTrack> trackList = workTrackService.getWorkTrackByTrackTypeList(orderId, workId, TrackConfigConsts.TRACK_CONTENT_ID_CANCEL);
        if (CollectionUtils.isEmpty(trackList)) {
            return null;
        }

        OrderWorkTrack cancelTrack = trackList.get(0);
        return cancelTrack;
    }

    /**
     * 工程师待取消状态
     *
     * @param orderWorkTrack
     * @return
     */
    @Override
    public Integer getMasterWaitCancelTrack(OrderWork orderWork, OrderWorkTrack orderWorkTrack) {
        // 已领单，未完结的跟单
        if (Objects.equals(OrderStatusConsts.WORK_STATUS_TAKE, orderWork.getStatus()) &&
            !Objects.equals(TrackConsts.TRACK_STATUS_FINISHED, orderWorkTrack.getTrackStatus())) {
            return GlobalConsts.YES;
        }

        return GlobalConsts.NO;
    }

    @Override
    public Integer getUserWaitCancelStatus(Long orderId, Long workId) {
        List<OrderWorkTrack> orderWorkTrackList = workTrackService.getWorkTrackByTrackTypeList(orderId, workId, TrackConfigConsts.TRACK_CONTENT_ID_CANCEL);
        return this.getUserWaitCancelStatus(orderWorkTrackList);
    }

    @Override
    public Integer getUserWaitCancelStatusSrcMaster(Long orderId, Long workId) {
        List<OrderWorkTrack> orderWorkTrackList = workTrackService.getWorkTrackByTrackTypeListSrcMaster(orderId, workId, TrackConfigConsts.TRACK_CONTENT_ID_CANCEL);
        return this.getUserWaitCancelStatus(orderWorkTrackList);
    }


    @Override
    public OrderWorkTrack getUserWaitCancelTrack(OrderWork orderWork) {
        if (orderWork == null) {
            return null;
        }

        // 只有进行中的 未完成的服务，才根据跟单获取取消时间
        if (!Objects.equals(orderWork.getResultStatus(), OrderStatusConsts.WORK_RESULT_DOING) || orderWork.getCompleteTime() != null) {
            return null;
        }

        // 查询取消的跟单
        List<OrderWorkTrack> trackList = workTrackService.getWorkTrackByTrackTypeList(orderWork.getOrderId(), orderWork.getWorkId(), TrackConfigConsts.TRACK_CONTENT_ID_CANCEL);
        if (CollectionUtils.isEmpty(trackList)) {
            return null;
        }

        OrderWorkTrack orderWorkTrack = this.getCancelTrack(trackList);
        return orderWorkTrack;
    }

    /**
     * 查找取消订单跟单
     *
     * @param trackList
     * @return
     */
    private OrderWorkTrack getCancelTrack(List<OrderWorkTrack> trackList) {
        if (CollectionUtils.isEmpty(trackList)) {
            return null;
        }
        // 取消工单跟单 && (未完结 or 同意取消)
        OrderWorkTrack orderWorkTrack = trackList.stream()
                .filter(track -> TrackConfigConsts.TRACK_CONTENT_ID_CANCEL.contains(track.getTrackType()))
                .filter(track -> !Objects.equals(TrackConsts.TRACK_STATUS_FINISHED, track.getTrackStatus()) || Objects.equals(track.getHandleResult(), TrackConsts.TRACK_CONTENT_TYPE_LEVEL_ONE))
                .findFirst().orElse(null);
        return orderWorkTrack;
    }

    public void trackReleaseStock(OrderWorkTrack track){

        List<Integer> releaseStockRestrictTrackContentIds = orderStockBService.releaseStockRestrictTrackContentIds();
        if (CollectionUtils.isEmpty(releaseStockRestrictTrackContentIds)) {
            releaseStockRestrictTrackContentIds = new ArrayList<>();
        }
        // 释放库存新增跟单内容id
        releaseStockRestrictTrackContentIds.add(TrackConsts.TRACK_CONTENT_ID_ENGINEER_CANCEL);
        // 释放库存
        if (!releaseStockRestrictTrackContentIds.contains(track.getTrackType())) {
            return;
        }

        if (!Objects.equals(track.getTrackStatus(), TrackConsts.TRACK_STATUS_PENDING)) {
            return;
        }
        try {
            orderStockBService.releaseStock(track.getOrderId(), track.getWorkId());
        } catch (OmsBaseException e) {
            log.error("{}跟单释放库存失败！{}", track.getWorkId(), e.getMessage());
        }
    }

    /**
     * 跟单变更处理
     * @param track
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void trackChangeHandle(OrderWorkTrack track) {
        this.deleteAndAddTrack(track);
        switch (track.getTrackType()) {
            case TrackConfigConsts.TRACK_CONTENT_ID_USER_CANCEL:
            case TrackConfigConsts.TRACK_CONTENT_ID_USER_CALLS_TO_REQUEST_CANCEL:
                userCancelHandle(track);
                break;
            case TrackConsts.TRACK_CONTENT_ID_ENGINEER_CANCEL:
                masterCancelHandle(track);
                break;
            case TrackConsts.TRACK_CONTENT_ID_DELIVERY:
                deliveryHandle(track);
                eventsNoticeBService.notice(track.getOrderId(),track.getWorkId(),OmsEventsConsts.ORDER_DELIVERY);
                break;
            case TrackConsts.TRACK_CONTENT_ID_WAIT_PART:
                waitPartHandle(track);
                eventsNoticeBService.notice(track.getOrderId(),track.getWorkId(),OmsEventsConsts.ORDER_WAIT_PART);
                break;
            default:
                break;
        }

        // 释放库存
        this.trackReleaseStock(track);
    }

    @Override
    public Date getAutoCancelTime(Date cancelDate) {
        TagsDRO delayTimeCodeMap = baseCodeService.getOneBaseCodeMap(com.zmn.consts.GlobalConsts.PLAT_MARK_ZMN, TagConsts.TAG_ONE_TYPE_NUMBER_AUTO_CANCEL_TIME, null);
        TagsDRO nighttimeCodeMap = baseCodeService.getOneBaseCodeMap(com.zmn.consts.GlobalConsts.PLAT_MARK_ZMN, TagConsts.TAG_ONE_TYPE_MINIMUM_NIGHTTIME, null);
        if (Objects.isNull(nighttimeCodeMap) || StringUtils.isBlank(nighttimeCodeMap.getName())) {
            return null;
        }
        Integer delayTime = delayTimeCodeMap.getTwoTypeId();
        String nighttime = nighttimeCodeMap.getName();
        String[] timeArr = nighttime.split("~");
        String[] startStr = timeArr[1].split(":");
        String[] endStr = timeArr[0].split(":");
        if (Objects.isNull(delayTime)) {
            return null;
        }
        // 自动取消时间
        LocalDateTime autoCancelTime;
        // 取消时间
        LocalDateTime cancelTime = LocalDateTime.ofInstant(cancelDate.toInstant(), ZoneId.systemDefault());
        // 当天凌晨
        LocalDateTime zeroTime = LocalDateTime.of(cancelTime.toLocalDate(), LocalTime.MIN);
        LocalDateTime start = zeroTime.plusHours(Integer.valueOf(startStr[0])).plusMinutes(Integer.valueOf(startStr[1]));
        LocalDateTime end = zeroTime.plusHours(Integer.valueOf(endStr[0])).plusMinutes(Integer.valueOf(endStr[1]));
        if (cancelTime.isBefore(start)) {
            autoCancelTime = start.plusMinutes(delayTime);
        } else if (cancelTime.isAfter(end)) {
            autoCancelTime = start.plusDays(1).plusMinutes(delayTime);
        } else {
            autoCancelTime = cancelTime.plusMinutes(delayTime);
        }
        return Date.from(autoCancelTime.atZone(ZoneId.systemDefault()).toInstant());
    }

    /**
     * 跟单-用户取消处理&&用户来电申请取消
     *
     * @param track
     */
    private void userCancelHandle(OrderWorkTrack track) {
        log.info("OmsOrderWorkTrackListener.track orderId={},trackStatus={},handleResult={}", track.getOrderId(), track.getTrackStatus(), track.getHandleResult());
        if (Objects.equals(TrackConsts.TRACK_STATUS_PROCESSING, track.getTrackStatus())) {
            return;
        }

        // 同步通知mos修改cancelApplyStatus字段
        orderChangeService.changeSyncDelayToMos(track.getOrderId(), System.currentTimeMillis() + 2000);

        OrderWork orderWork = orderWorkService.findOrderWorkByKey(track.getOrderId(), track.getWorkId());

        // 房屋业务
        if (Objects.equals(orderWork.getServCategId(), ProductConsts.SERV_CATEG_WATERPROOF) ||
                Objects.equals(orderWork.getServCategId(), ProductConsts.SERV_CATEG_METOPE) ||
                Objects.equals(orderWork.getServCategId(), ProductConsts.SERV_CATEG_KITCHEN_TOILET)) {
            return;
        }

        // 特殊渠道
        ConfOrderChannel confOrderChannel = confOrderChannelService.findByKey(orderWork.getChannelId());
        if (Objects.nonNull(confOrderChannel) && Objects.equals(confOrderChannel.getSupportBacktracking(), GlobalConsts.NO)) {
            return;
        }

        // 夜间发起跟单师傅领单&&上门后，用户取消订单，不进工程师APP：“待取消”
        if (orderWork.getStatus() < OrderStatusConsts.WORK_STATUS_TAKE) {
            return;
        }

        if (NumberUtil.isNullOrZero(orderWork.getDepositAmount())) {
            // 修改工程师列表取消状态
            MasterWorking masterWorking = new MasterWorking();
            masterWorking.setWorkId(track.getWorkId());
            masterWorking.setWaitCancel(this.getMasterWaitCancelTrack(orderWork, track));
            masterWorkingService.updateMasterWorking(masterWorking);
        }
        // 推送消息&&刷新列表
        this.refushMasterAppList(orderWork, track);
    }

    /**
     * 跟单-工程师取消处理
     *
     * @param track
     */
    private void masterCancelHandle(OrderWorkTrack track) {
        Integer waitCancel = Objects.equals(TrackConsts.TRACK_STATUS_FINISHED, track.getTrackStatus()) && Objects.equals(2, track.getHandleResult())
                ? GlobalConsts.NO : GlobalConsts.YES;

        MasterWorking masterWorking = new MasterWorking();
        masterWorking.setWorkId(track.getWorkId());
        masterWorking.setWaitCancel(waitCancel);
        masterWorkingService.updateMasterWorking(masterWorking);

        this.refushMasterAppList(track);
    }

    /**
     * 拉修跟单处理
     * @param track
     */
    private void deliveryHandle(OrderWorkTrack track){
        Integer delivery = Objects.equals(TrackConsts.TRACK_STATUS_FINISHED, track.getTrackStatus()) ? GlobalConsts.NO : GlobalConsts.YES;

        OrderWork updateOrderWork = new OrderWork();
        updateOrderWork.setOrderId(track.getOrderId());
        updateOrderWork.setWorkId(track.getWorkId());
        updateOrderWork.setUpdateTime(new Date());
        updateOrderWork.setDelivery(delivery);
        masterWorkService.updateTrackStatus(updateOrderWork);

        MasterWorking masterWorking = new MasterWorking();
        masterWorking.setWorkId(track.getWorkId());
        masterWorking.setDelivery(delivery);
        masterWorkingService.updateMasterWorking(masterWorking);

        this.refushMasterAppList(track);
    }

    /**
     * 待件跟单处理
     * @param track
     */
    private void waitPartHandle(OrderWorkTrack track) {
        Integer waitPart = Objects.equals(TrackConsts.TRACK_STATUS_FINISHED, track.getTrackStatus()) ? GlobalConsts.NO : GlobalConsts.YES;

        OrderWork updateOrderWork = new OrderWork();
        updateOrderWork.setOrderId(track.getOrderId());
        updateOrderWork.setWorkId(track.getWorkId());
        updateOrderWork.setUpdateTime(new Date());
        updateOrderWork.setWaitPart(waitPart);
        masterWorkService.updateTrackStatus(updateOrderWork);

        MasterWorking masterWorking = new MasterWorking();
        masterWorking.setWorkId(track.getWorkId());
        masterWorking.setWaitPart(waitPart);
        masterWorkingService.updateMasterWorking(masterWorking);

        this.refushMasterAppList(track);
    }

    private void refushMasterAppList(OrderWorkTrack track) {
        OrderWork orderWork = orderWorkService.findOrderWorkByKey(track.getOrderId(), track.getWorkId());
        if (NumberUtil.isNullOrZero(orderWork.getMasterId())) {
            return;
        }
        this.refushMasterAppList(orderWork, track);
    }

    private void refushMasterAppList(OrderWork orderWork, OrderWorkTrack track) {
        // TODO 发通知统一挪到 跟单系统 com.zmn.track.business.interfaces.log.TrackLogNodeNoticeBService
        if (TrackConfigConsts.TRACK_CONTENT_ID_CANCEL.contains(track.getTrackType())) {
            this.sendAppMsg(orderWork, track);
        }

        // 刷新工程师app列表
        if (Objects.equals(track.getTrackStatus(), TrackConsts.TRACK_STATUS_PENDING) || Objects.equals(track.getTrackStatus(), TrackConsts.TRACK_STATUS_FINISHED)) {
            //touchModifyRemoteService.saveWorkVersion(orderWork.getMasterId(), null);
            mqProviderService.sendEngineerWorkVersion(orderWork.getMasterId(), null);
        }
    }

    private void sendAppMsg(OrderWork orderWork, OrderWorkTrack track) {
        // 发送消息通知
        if (!Objects.equals(track.getTrackStatus(), TrackConsts.TRACK_STATUS_PENDING)) {
            return;
        }
        log.info("com.zmn.oms.business.impl.worktrack.WorkTrackBServiceImpl.sendAppMsg: workId={} trackId={}", orderWork.getWorkId(), track.getTrackId());
        Map<String, String> params = Maps.newHashMap();
        params.put("order_id", String.valueOf(orderWork.getOrderId()));
        if (NumberUtil.isNotNullOrZero(orderWork.getDepositAmount())) {
            messageSendAppService.pushAppMessageInfo(MessageConsts.ZMN_MSG_CANCEL_APPLY, JSON.toJSONString(params), orderWork);
            return;
        }
        Date autoCancelTime = getAutoCancelTime(track.getCreateTime());
        if(Objects.isNull(autoCancelTime)){
            return;
        }
        String autoCancelTimeStr = DateUtil.toString(autoCancelTime, "HH:mm:ss");
        params.put("time", autoCancelTimeStr);
        log.info("跟单{} 用户取消跟单时间：{} 自动取消时间：{}", track.getTrackId(), track.getCreateTime(), autoCancelTimeStr);
        messageSendAppService.pushAppMessageInfo(MessageConsts.ZMN_MSG_NO_DEPOSIT_CANCEL_APPLY, JSON.toJSONString(params), orderWork);
    }
}